package sm.hibernate.type;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;

import org.hibernate.HibernateException;
import org.hibernate.usertype.ParameterizedType;

import sm.codec.type.RC;
import sm.codec.type.Struct;
import sm.def.Type;
import sm.util.SMMap;

import com.google.gson.Gson;

public class RCStructureType extends AbstractRCCompositeType implements
		ParameterizedType {

	private boolean isDescriptor;

	private Map<String, Object> typedef;

	@Override
	public void setParameterValues(Properties parameters) {
		String jsonStructure = parameters.getProperty("typedef");
		Gson gson = new Gson();
		typedef = gson.fromJson(jsonStructure, Map.class);

		String descriptor = parameters.getProperty("descriptor");
		if (descriptor != null) {
			isDescriptor = Boolean.parseBoolean(descriptor);
		}
	}

	@Override
	public Class returnedClass() {
		return Map.class;
	}

	@Override
	public Object deepCopy(Object value) throws HibernateException {
		return value;
	}

	@Override
	protected Object rcToValue(RC rc, Object owner) {
		Object value = rc;
		if (rc != null) {
			List<Object> values = rc.getValues();
			if (values != null && values.size() == 1) {
				value = values.get(0);
				if (value instanceof Struct) {
					Struct struct = (Struct) value;
					if (struct.getType() == Type.STRUCTURE_TYPE) {
						Map<String, Object> structure = RCTypeHelper
								.structureToMap(struct.getValue(), typedef);
						if (isDescriptor) {
							Map<String, Object> descriptor = (Map<String, Object>) owner;

							if (descriptor != null) {
								for (Entry<String, Object> entry : structure
										.entrySet()) {
									String fieldName = entry.getKey();
									Object fieldValue = entry.getValue();
									// skip DB fields
									if (!descriptor.containsKey(fieldName)) {
										descriptor.put(fieldName, fieldValue);
									}
								}
							}
						}
						value = structure;
					}
				}
			}

		}
		return value;
	}

	@Override
	protected RC valueToRC(Object value) {
		RC rc = null;
		if (value != null) {
			if (value instanceof RC) {
				rc = (RC) value;
			} else {
				if (value instanceof SMMap) {
					SMMap structure = (SMMap) value;
					List<Object> values = RCTypeHelper.mapToStructure(
							structure, typedef);
					value = new Struct(values, Type.STRUCTURE_TYPE);
				}
				List<Object> values = new ArrayList<Object>();
				values.add(value);
				rc = new RC(values);
			}
		}

		return rc;
	}
}
